from flask import Flask, render_template, request
import numpy as np
import pickle
import pandas as pd
import matplotlib.pyplot as plt
import io
import base64

app = Flask(__name__)

# 设置 matplotlib 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

@app.route('/', methods=['GET', 'POST'])
def index():
    #初始化变量用于存储预测结果、图表数据和错误信息
    prediction = None
    plot_url_avg_salary = None
    plot_url_education_salary = None
    error_message = None

    try:
        # 读取 CSV 文件
        df = pd.read_csv('拉钩网招聘_数据分析_上海.csv')
        # CSV 文件中有 '工作地点'、'薪资' 和 '学历' 三列
        # 处理薪资列，提取薪资范围的平均值
        def get_avg_salary(salary_str):
            try:
                if '-' in salary_str:
                    #使用 split('-') 将范围格式的薪资拆分为上下限两部分
                    #使用 map(int, ...) 将字符串类型的薪资数值转换为整数
                    low, high = map(int, salary_str.replace('k', '').split('-'))
                    return (low + high) / 2
                else:
                    return int(salary_str.replace('k', ''))
            except ValueError:
                return np.nan
        #将 get_avg_salary 函数应用到 DataFrame 的 薪资 列，并将结果存入新列 平均薪资
        df['平均薪资'] = df['薪资'].apply(get_avg_salary)

        # 按地区分组计算平均薪资
        #按工作地点列对 DataFrame 进行分组，将同一地区的数据归为一组
        #对每个分组的平均薪资列计算均值（mean）
        #.mean().reset_index()重置索引，将分组依据的工作地点列从索引转换为普通列
        avg_salary_by_location = df.groupby('工作地点')['平均薪资'].mean().reset_index()

        locations = avg_salary_by_location['工作地点']
        avg_salaries = avg_salary_by_location['平均薪资']

        # 绘制地区和平均薪资关系的直方图
        plt.figure(figsize=(10, 6))
        plt.bar(locations, avg_salaries)
        plt.xlabel('地区')
        plt.ylabel('平均薪资（k）')
        plt.title('地区和平均薪资的关系')
        plt.xticks(rotation=45) #rotation=45：将横轴标签（地区名称）旋转 45 度

        # 将图像保存到内存中
        img_avg_salary = io.BytesIO()  #创建一个二进制数据流（BytesIO）对象
        plt.savefig(img_avg_salary, format='png')
        img_avg_salary.seek(0) #将数据流的读取指针重置到起始位置 确保后续的读取操作（如 base64 编码）能从数据流开头获取完整数据

        # 将图像转换为 base64 编码
        plot_url_avg_salary = base64.b64encode(img_avg_salary.getvalue()).decode()

        # 绘制学历和薪资的箱线图
        plt.figure(figsize=(10, 6))
        df.boxplot(column='平均薪资', by='学历')
        plt.xlabel('学历')
        plt.ylabel('平均薪资（k）')
        plt.title('学历和薪资的箱线图')
        plt.suptitle('')  # 去除默认的子图标题

        # 将图像保存到内存中
        img_education_salary = io.BytesIO()
        plt.savefig(img_education_salary, format='png')
        img_education_salary.seek(0)

        # 将图像转换为 base64 编码
        plot_url_education_salary = base64.b64encode(img_education_salary.getvalue()).decode()

    except FileNotFoundError:
        error_message = "未找到 CSV 文件，请检查文件路径和文件名。"
    except Exception as e:
        error_message = f"处理数据时出错: {str(e)}"

    if request.method == 'POST':
        # 获取用户输入的特征值
        experience = float(request.form['experience'])
        education = request.form['education']
        location = request.form['location']

        try:
            with open('LR.pkl', 'rb') as file:
                LR = pickle.load(file)
            with open('OHE_location.pkl', 'rb') as file:
                OHE_location = pickle.load(file)
            with open('OHE_edu.pkl', 'rb') as file:
                OHE_edu = pickle.load(file)

            my_edu = OHE_edu.transform([[education]]).toarray()
            my_location = OHE_location.transform([[location]]).toarray()
            my_exp = np.array([[experience]])
            X = np.concatenate([my_edu, my_location, my_exp], axis=1)

            # 进行预测
            prediction = LR.predict(X)[0]
            # 保留三位小数
            prediction = round(prediction, 3)
        except Exception as e:
            error_message = f"预测薪资时出错: {str(e)}"

    return render_template('index.html', prediction=prediction, plot_url_avg_salary=plot_url_avg_salary, plot_url_education_salary=plot_url_education_salary, error_message=error_message)

if __name__ == '__main__':
    app.run(debug=True)